
package carmadness.controller;

import carmadness.model.Facade;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.regex.*;

/**
 * Tesztelésre szolgáló konzolos bemenetet kezelő controller.
 * 
 * @author Ujhelyi
 * @version 1.0
 * @created 10-Apr-2010 2:32:38 PM
 */
public class ConsoleController extends Controller
{
	private class CommandParser
	{
		private class Command
		{
			public String name;
			public LinkedList<String> arguments = new LinkedList<String>();

			/**
			 * Az argumentum listát tömbbé konvertálja.
			 * 
			 * @return Az argumentumok tömbje.
			 */
			private Object[] getArgs()
			{
				Object[] args = new Object[arguments.size()];
				for ( int i = 0; i < args.length; i++ )
				{
					String arg = arguments.get( i );
					args[i] = arg.equals( "*" ) ? null : arguments.get( i );
				}

				return args;
			}

			/**
			 * Visszaadja az argumentumok típusainak tömbjét. (Minden parancs
			 * String paramétereket vár.)
			 * 
			 * @return Argumentumok típusainak tömbje.
			 */
			private Class[] getArgTypes()
			{
				Class[] types = new Class[arguments.size()];
				for ( int i = 0; i < types.length; i++ )
					types[i] = String.class;

				return types;
			}

			/**
			 * Meghívja a konzolban kiadott parancshoz tartozó metódust.
			 * 
			 * @param target
			 *            Az obejktum amin megkíséreljük meghívni a keresett
			 *            metódust.
			 */
			public void invoke( Object target )
			{
				try
				{
					System.out.println( name );

					try
					{
						target.getClass().getDeclaredMethod( name, getArgTypes() ).invoke( target, getArgs() );
					}
					catch ( NoSuchMethodException e )
					{
						System.out.println( "! Invalid command." );
					}
				}
				catch ( Exception e )
				{
					e.printStackTrace();
				}
			}
		}

		private Pattern commandPattern = Pattern.compile( "(\\w+)\\((.*)\\)" );
		private Pattern argumentPattern = Pattern.compile( "\"[^\"]*\"|[\\w\\d]+|\\*" );

		/**
		 * Feldolgozza a parancssorból kapott stringet.
		 * 
		 * @param commandString
		 *            A parancssorból kapott feldolgozatlan string.
		 * @return A parancsot leíró objektum.
		 */
		public Command parse( String commandString )
		{
			Matcher commandMatcher = commandPattern.matcher( commandString );
			if ( commandMatcher.matches() )
			{
				Command command = new Command();
				command.name = commandMatcher.group( 1 );

				Matcher argumentMatcher = argumentPattern.matcher( commandMatcher.group( 2 ) );
				while ( argumentMatcher.find() )
				{
					String arg = argumentMatcher.group();
					command.arguments.add( arg.startsWith( "\"" ) ? arg.substring( 1, arg.length() - 1 ) : arg );
				}

				return command;
			}

			return null;
		}
	}

	public ConsoleController( InputStream in )
	{
		BufferedReader stdinReader = new BufferedReader( new java.io.InputStreamReader( in ) );
		CommandParser parser = new CommandParser();

		try
		{
			while ( true )
			{
				String commandLine = stdinReader.readLine();
				if ( commandLine == null ) break;

				CommandParser.Command command = parser.parse( commandLine );
				if ( command != null ) command.invoke( Facade.getInstance() );
			}
		}
		catch ( IOException e )
		{
			System.out.println( "! Cannot read from stdin." );
		}
	}
}
